2023/12/233826字符

浏览器渲染原理

当浏览器的网络线程收到 HTML 文档后,会产生一个渲染任务,并将其交给浏览器消息队列。 在事件循环机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。

渲染流程

一、解析

  1. 渲染主线程解析 HTML;
  2. 当遇到 link 元素,浏览器会启动一个预解析器,渲染主线程继续向后解析
  3. 网络线程将 CSS 下载;
  4. 预解析器对 CSS 进行解析;
  5. 当遇到 script 元素(JS 可能会改变 DOM 结构)
  6. 停止解析 HTML,转而将 .js 文件下载好;
  7. 启动 V8 引擎解析执行;

解析完成后,得到 DOM 树和 CSSOM 树,浏览器的默认样式、内部样式、外部样式、行内样式均会包含在 CSSOM 树中

二、样式计算

  1. 层叠冲突
  2. 比较源的重要性 - 用户代理样式:浏览器会有一个基本的样式表来给任何网页设置默认样式; - 用户样式:可以使用自定义样式表定制使用体验; - 页面作者样式:网页的作者可以定义文档的样式;
  3. 比较优先级(CSS 权重
  4. 比较次序(样式覆盖)
  5. 样式继承
  6. 使用默认值(浏览器开发时所设置的默认样式)

三、生成布局树

给 DOM 树的节点依次计算它的最终样式 Computed Style,将预设值变为绝对值;

  • DOM 树与 CSSOM 树生成 Layout 树(宽高、位置等几何信息)
    • head meta link 这些标签默认样式表设置为不显示,也就没有几何信息,所以参与 Layout 树的生成;
    • DOM 树中伪元素虽然不存在,但它们拥有几何信息,也会参数 Layout 树的渲染;
    • 匿名行盒/块盒等都会导致 DOM 树和 Layout 树无法一一对应。

四、分层(老版本浏览器中没有)

  • 主线程会使用一套复杂的策略对整个 Layout 树进行分层;
  • 分层的好处在于将来某一个层改变后,仅会对该层进行后续处理,从而提升效率;
  • 滚动条、堆叠上下文、transform、opacity 等样式都会或多或少的影响分层结果,也可以通过 will-change 属性更大程度的影响分层结果。

五、生成绘制指令(canvas)

将笔移动到位置 x,y
宽:w,高:h 的矩形
填充颜色 red
  • 绘制完交给合成线层

六、分块

  • 合成线程首先对每个图层进行分块,将其划分为更多的小区域。它会从线程池中拿取多个线程来完成分块工作

七、光栅化(像素点)

  • 合成线程将块信息交给 GPU 进程,GPU 将开启多个线程完成光栅化,并且优先处理靠近视口区域的块。
  • 合成线程拿到每个层,每个块的位图,生成一个个指引信息。

八、绘制

  • 指引会标识出应该画到哪个位置,以及会考虑到旋转、缩放等变形;
  • 变形发生在合成线程,与渲染主线程无关,所以效率要高 transform;
  • 绘制图像信息
渲染主线程: 解析  样式计算  布局  分层  绘制
合成线程:                                 分块
GPU 多个绘制线程:                               光栅化  绘制

什么是回流

  • 回流的本质是重新计算 layout 树,导致后续步骤重新触发(回流即会重绘);
  • 而重绘没有发生在渲染主线程内,所以性能上要好很多。

为什么 transform 的效率高?

transform 既不会影响布局也不会影响绘制指令,它影响的只是渲染流程的最后一个绘制阶段。 绘制并不发生在渲染主线程,所以 transform 的变化几乎不影响渲染主线程。反之,无论渲染主线程如何忙碌,也不会影响 transform 变化。